using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using DevExpress.XtraEditors;
using DevExpress.XtraGrid.Views.Grid.ViewInfo;
using DevExpress.XtraTreeList;
using DevExpress.XtraTreeList.Nodes;
using Movements.DataSet;

namespace Movements.Controls
{
    public partial class ProductSetupXtraUserControl : XtraUserControl, IProductSetup
    {
        private Controller _controller;
        private ArvoreProdutoDataSet _productsTreeData;

        #region Properties

        public Controller Controller
        {
            set
            {
                _controller = value;
                _controller.ProductTreeSaved += delegate { SetTreeDataSource(); };
                _controller.ProductSaved += delegate { SetDataSource(); };
                SetDataSource();
            }
        }

        #endregion

        public ProductSetupXtraUserControl()
        {
            InitializeComponent();
            gridControl.MouseMove += GridControlMouseMove;
            treeList.CellValueChanged += TreeListCellValueChanged;
            treeList.ShowingEditor += TreeListShowingEditor;
            treeList.DragEnter += TreeListDragEnter;
            treeList.DragOver += TreeListDragOver;
            treeList.DragDrop += TreeListDragDrop;
        }

        #region Private Methods

        private void SetGridDataSource()
        {
            ProdutoDataSet dataSet = _controller.GetProducts();
            gridControl.DataSource = null;
            gridControl.DataSource = dataSet;
            gridControl.DataMember = dataSet.Produto.TableName;
        }

        public void AddRootLevel()
        {
            var dataSet = new ArvoreProdutoDataSet();
            var productTree = dataSet.ArvoreProduto.NewArvoreProdutoRow();
            productTree.Id = -1;
            productTree.Nome = "Grupo";
            productTree.Tipo = (int)ProductTreeType.Folder;
            dataSet.ArvoreProduto.AddArvoreProdutoRow(productTree);
            _controller.SaveProductTree(dataSet);
            var treeListNode = treeList.FindNodeByKeyID(dataSet.ArvoreProduto[0].Id);
            treeList.FocusedNode = treeListNode;
            treeList.ShowEditor();
        }

        private void SetTreeDataSource()
        {
            _productsTreeData = _controller.ProductsTree();
            treeList.DataSource = null;
            treeList.DataSource = _productsTreeData;
            if (_productsTreeData.ArvoreProduto.Count == 0)
                AddRootLevel();
        }

        private void SetDataSource()
        {
            SetTreeDataSource();
            SetGridDataSource();
        }

        private List<DictionaryEntry> GetSelectedProducts()
        {
            var products = new List<DictionaryEntry>();
            foreach (var handle in gridView.GetSelectedRows())
            {
                var product = (ProdutoDataSet.ProdutoRow)gridView.GetDataRow(handle);
                products.Add(new DictionaryEntry(product.Id, product.Designacao));
            }
            return products;
        }

        private void AddProducts(IDataObject dataObject, string format, TreeListNode parentNode)
        {
            if (!dataObject.GetDataPresent(format))
                return;
            var products = (List<DictionaryEntry>)dataObject.GetData(format);
            if (products.Count == 0)
                return;
            var dataSet = new ArvoreProdutoDataSet();
            long id = 0;
            foreach (DictionaryEntry product in products)
            {
                var parentNodeId = Convert.ToInt32(parentNode["Id"]);
                var productTree = dataSet.ArvoreProduto.NewArvoreProdutoRow();
                productTree.Id = id--;
                productTree.IdPai = parentNodeId;
                productTree.Nome = product.Value.ToString();
                productTree.Tipo = (int)ProductTreeType.Product;
                productTree.IdProduto = Convert.ToInt64(product.Key);
                dataSet.ArvoreProduto.AddArvoreProdutoRow(productTree);
            }
            _controller.SaveProductTree(dataSet);
            var treeListNode = treeList.FindNodeByKeyID(dataSet.ArvoreProduto[0].Id);
            treeList.FocusedNode = treeListNode;
        }

        private List<long> GetProductTreeChildIds(long productTreeId)
        {
            var childIds = new List<long>();
            foreach (ArvoreProdutoDataSet.ArvoreProdutoRow productTree in _productsTreeData.ArvoreProduto)
            {
                if (productTree.RowState == DataRowState.Deleted)
                    continue;
                if (!productTree.IsIdPaiNull() && productTree.IdPai == productTreeId)
                    childIds.Add(productTree.Id);
            }
            return childIds;
        }

        private void DeleteProductTree(long productTreeId)
        {
            var productTreeChildIds = GetProductTreeChildIds(productTreeId);
            foreach (var productTreeChildId in productTreeChildIds)
                DeleteProductTree(productTreeChildId);
            _controller.DeleteProductTree(productTreeId);
        }

        #endregion

        #region IProductManagement

        public void AddGroup()
        {
            var parentNode = treeList.FocusedNode;
            if (Convert.ToInt32(parentNode["Tipo"]) == (int)ProductTreeType.Product)
                parentNode = parentNode.ParentNode;
            var parentNodeId = Convert.ToInt32(parentNode["Id"]);
            var dataSet = new ArvoreProdutoDataSet();
            var productTree = dataSet.ArvoreProduto.NewArvoreProdutoRow();
            productTree.Id = -1;
            productTree.IdPai = parentNodeId;
            productTree.Nome = "Grupo" + parentNodeId;
            productTree.Tipo = (int)ProductTreeType.Folder;
            dataSet.ArvoreProduto.AddArvoreProdutoRow(productTree);
            _controller.SaveProductTree(dataSet);
            var treeListNode = treeList.FindNodeByKeyID(dataSet.ArvoreProduto[0].Id);
            treeList.FocusedNode = treeListNode;
            treeList.ShowEditor();
        }

        public void Remove()
        {
            var focusedNode = treeList.FocusedNode;
            if (focusedNode == null)
                return;
            if (focusedNode["IdPai"] == null)
                return;
            if(MessageBox.Show(this, "Tem a certeza que deseja eliminar o registo?", "Produto", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) == DialogResult.No)
                return;
            var dataRowView = (DataRowView)treeList.GetDataRecordByNode(focusedNode);
            var productTree = (ArvoreProdutoDataSet.ArvoreProdutoRow)dataRowView.Row;
            DeleteProductTree(productTree.Id);
        }

        #endregion

        void GridControlMouseMove(object sender, MouseEventArgs e)
        {
            GridHitInfo hitInfo = gridView.CalcHitInfo(new Point(e.X, e.Y));
            if (e.Button == MouseButtons.Left && hitInfo.InRow)
                gridControl.DoDragDrop(new DataObject("Produto", GetSelectedProducts()), DragDropEffects.Copy);
        }

        void TreeListShowingEditor(object sender, CancelEventArgs e)
        {
            var node = treeList.FocusedNode;
            if (Convert.ToInt32(node["Tipo"]) == (int)ProductTreeType.Product || node["IdPai"] == Convert.DBNull)
                e.Cancel = true;
        }

        void TreeListCellValueChanged(object sender, CellValueChangedEventArgs e)
        {
            var dataRowView = (DataRowView)treeList.GetDataRecordByNode(e.Node);
            var productTree = (ArvoreProdutoDataSet.ArvoreProdutoRow)dataRowView.Row;
            productTree.Nome = e.Value.ToString();
            _controller.UpdateProductTree(productTree.Id, productTree.Nome);
            var treeListNode = treeList.FindNodeByKeyID(productTree.Id);
            treeList.FocusedNode = treeListNode;
        }

        static void TreeListDragEnter(object sender, DragEventArgs e)
        {
            e.Effect = e.Data.GetDataPresent("Produto") ? DragDropEffects.Copy : DragDropEffects.None;
        }

        void TreeListDragOver(object sender, DragEventArgs e)
        {
            TreeListHitInfo hi = treeList.CalcHitInfo(treeList.PointToClient(new Point(e.X, e.Y)));
            TreeListNode node = hi.Node;
            if (e.Data.GetDataPresent("Produto") && node != null && Convert.ToInt32(node["Tipo"]) == (int)ProductTreeType.Folder)
                e.Effect = DragDropEffects.Copy;
            else
                e.Effect = DragDropEffects.None;
        }

        void TreeListDragDrop(object sender, DragEventArgs e)
        {
            TreeListHitInfo hi = treeList.CalcHitInfo(treeList.PointToClient(new Point(e.X, e.Y)));
            TreeListNode node = hi.Node;
            AddProducts(e.Data, "Produto", node);
        }
    }
}
